#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>

#define SIZE 256
#define ZERO '\0'
#define SEP " "
#define NUM 32

#define None_Redir 0
#define In_Redir   1
#define Out_Redir  2
#define App_Redir  3

#define SkipSpace(cmd,pos) do{\
  while(1){\
    if(isspace(cmd[pos])) pos++;\
    else break;\
  }\
}while(0)

int redir_type=None_Redir;
char* filename=NULL;



char* gArgv[NUM];

const char* GetUser()
{
  const char* p=getenv("USER");
  if(p==NULL)  return "None";
  return p;
}

const char* GetHostName()
{
  const char* p=getenv("HOSTNAME");
  if(p==NULL)  return "None";
  return p;
}

const char* GetCwd()
{
  const char* p=getenv("PWD");
  if(p==NULL)  return "None";
  return p;
}

void GetCwd2(const char** p)
{
  //1.*p指向最后一个字符
  (*p)+=strlen(*p)-1;
  //2.让*p指向从后往前的第一个“/”
  while((**p)!='/')
    (*p)--;
}

void MakeCommandLine()
{
  const char* user=GetUser();
  const char* hostname=GetHostName();
  const char* cwd=GetCwd();

  //让cwd指向最后一个"/"
  GetCwd2(&cwd);
  printf("[%s@%s %s]> ",user,hostname,strlen(cwd)==1?"/":cwd+1);
}

int GetUserCommand(char commandline[],size_t sz)
{
  char* s=fgets(commandline,sz,stdin);
  if(s==NULL)
    exit(1);
  commandline[strlen(commandline)-1]=ZERO;
  return strlen(commandline);
}



void SplitCommand(char commandline[])
{
  char* s=strtok(commandline,SEP); 
  gArgv[0]=s;
  int i=1;
  while((gArgv[i++]=strtok(NULL,SEP)))
    ;
}

int exit_code=0;

void ExecuteCommand()
{
  pid_t id=fork();
  if(id<0)  exit(3);
  else if(id==0)
  {
    //child
    if(redir_type==In_Redir)
    {
      int fd=open(filename,O_RDONLY);
      dup2(fd,0);
    }
    else if(redir_type==Out_Redir)
    {
      int fd=open(filename,O_WRONLY | O_CREAT | O_TRUNC ,0666);
      dup2(fd,1);
    }
    else if(redir_type==App_Redir)
    {
      int fd=open(filename,O_WRONLY | O_CREAT | O_APPEND ,0666);
      dup2(fd,1);
    }
    else 
    {}


    execvp(gArgv[0],gArgv);
    exit(errno);
  }
  else 
  {
    //parent
    int status=0;
    pid_t rid=waitpid(id,&status,0);
    if(rid>0)
    {
      //等待成功
      if(WIFEXITED(status))//代码跑完
      {
        exit_code=WEXITSTATUS(status);
        printf("child quit success,exit_code=%d\n",exit_code);
      }
      else //代码执行时，出现异常，提前退出了
        printf("child quit unnormally\n");
    }
  }
}

const char* GetHome()
{
  const char* p=getenv("HOME");
  if(p==NULL)  return "None";
  return p;
}

void CD()
{
  //1.修改/proc的cwd
  const char* path=gArgv[1];
  if(path==NULL)  path=GetHome();
  chdir(path);

  //2.修改环境变量PWD
  char tmp[SIZE];
  char cwd[SIZE];
  getcwd(tmp,sizeof(tmp));
  snprintf(cwd,sizeof(cwd),"PWD=%s",tmp);
  putenv(cwd);
}


int CheckBuildin()
{
  int ret=0;
  if(strcmp(gArgv[0],"cd")==0)
  {
    ret=1;
    CD();
  }
  else if(strcmp(gArgv[0],"echo")==0 && strcmp(gArgv[1],"$?")==0)
  {
    ret=1;
    printf("%d\n",exit_code);
  }
  return ret;
}


void Redir_Operation(char cmd[],int pos)
{
  cmd[pos++]=0;
  SkipSpace(cmd,pos);
  filename=cmd+pos;
}

//ls -l -a > log.txt
void CheckRedir(char cmd[],int sz)
{
  int pos=0;
  while(pos<sz)
  {
    if(cmd[pos]=='<')
    {
      redir_type=In_Redir;
      Redir_Operation(cmd,pos);
    }
    else if(cmd[pos]=='>')
    {
      if(cmd[pos+1]=='>')
      {
        redir_type=App_Redir;
        cmd[pos]=0;
        Redir_Operation(cmd,pos+1);
      }
      else 
      {
        redir_type=Out_Redir;
        Redir_Operation(cmd,pos);
      }
    }
    else 
    {
      pos++;
    }
  }
}



int main()
{
  while(1)
  {
    //1.输出命令行  [zy@localhost myshell3]$ 
    MakeCommandLine();
    
    //2.获取用户命令字符串
    char commandline[SIZE];
    int n=GetUserCommand(commandline,sizeof(commandline));
    if(n<0)
      break;
    else if(n==0)
      continue;

    //ls -l -a > log.txt
    //2.1 checkredir
    CheckRedir(commandline,n);

    //2.2 debug
//    printf("commandline:%s\n",commandline);
//    printf("redir_type:%d\n",redir_type);
//    printf("filename:%s\n",filename);
//

    //3.分割命令行字符串
    SplitCommand(commandline);
   
    //4.判断是否是内建命令
    int ret=CheckBuildin();
    if(ret)
      continue;
  
    //4.执行命令
    ExecuteCommand();
  }
  return 0;
}


//int main()
//{
//  while(1)
//  {
//
//    //1.输出命令行  [zy@localhost myshell3]$ 
//    MakeCommandLine();
//  
//    //2.获取用户命令字符串
//    char commandline[SIZE];
//    int n=GetUserCommand(commandline,sizeof(commandline));
//    if(n<0)  break;
//    else if(n==0) continue;
//    
//    //3.分割命令字符串
//    SplitCommand(commandline);
//  
//    //4.判断是否是内建命令
//    int ret=CheckBuildin();
//    if(ret)
//      continue;
//  
//    //5.执行命令
//    ExecuteCommand();
//  
//
//  }
//
//  return 0;
//}
//



